package com.xuecheng.search.service;

import com.xuecheng.framework.domain.course.CoursePub;
import com.xuecheng.framework.domain.course.response.TeachplanMediaPub;
import com.xuecheng.framework.domain.search.CourseSearchParam;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//搜索课程信息Day11
@Service
public class EsCourseService {
    //yml文件引入 "表名"
    @Value("${xuecheng.course.index}")
    private String index;

    //yml文件引入 "类型"
    @Value("${xuecheng.course.type}")
    private String type;

    //yml文件引入  "显示字段"
    @Value("${xuecheng.course.source_field}")
    private String source_field;


    //ay_15@9:yml文件引入 "表名"
    @Value("${xuecheng.media.index}")
    private String media_index;
    //ay_15@9:yml文件引入 "类型"
    @Value("${xuecheng.media.type}")
    private String media_type;
    //Day_15@9:yml文件引入  "显示字段"
    @Value("${xuecheng.media.source_field}")
    private String media_source_field;

    //注入执行客户端
    @Autowired
    RestHighLevelClient restHighLevelClient;

    //搜索课程信息Day11
    public QueryResponseResult<CoursePub> list(int page , int size, CourseSearchParam courseSearchParam){
        //非空判断
        if (courseSearchParam==null){
            courseSearchParam = new CourseSearchParam();
        }

        //1.创建搜索请求对象   --不写死,以yml文件引入
        SearchRequest searchRequest = new SearchRequest(index);
        //2.创建搜索类型
        searchRequest.types(type);


        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //3.过滤源字段
        String [] sourse_field_array = source_field.split(",");
        searchSourceBuilder.fetchSource(sourse_field_array,new String[]{});

        //6.创建boolean查询对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();


        //5.搜索条件

        //7.根据关键字搜索
        if (StringUtils.isNotEmpty(courseSearchParam.getKeyword())){
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeyword(), "name", "description", "teachplan")
                    .minimumShouldMatch("70%")
                    .field("name", 10);
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }
        //--------------按分类和难度等级搜索 Day_11_25--------------------------------------------------
        //搜索条件
        //根据关键字搜索

        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){
            //根据一级分类
            boolQueryBuilder.filter(QueryBuilders.termQuery("mt",courseSearchParam.getMt()));
        }
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){
            //根据二级分类
            boolQueryBuilder.filter(QueryBuilders.termQuery("st",courseSearchParam.getSt()));
        }
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){
            //根据难度等级
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
        }
        //--------------------------------------------------------------------
        //7.设置booleanBuilder到searchSourceBuilder
        searchSourceBuilder.query(boolQueryBuilder);

//Day12-----------------------------------------------------
        //1.设置分页参数
        if(page<=0){
            page = 1;
        }
        if(size<=0){
            size = 12;
        }
        //起始记录下标
        int from  = (page-1)*size;
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);

        //2.设置高亮
        //设置高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮 的 样式
        highlightBuilder.preTags("<font class='eslight'>");
        //设置高亮 的 样式
        highlightBuilder.postTags("</font>");
        //设置高亮字段   那个字段要高亮
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        searchSourceBuilder.highlighter(highlightBuilder);

//Day12-----------------------------------------------------
        searchRequest.source(searchSourceBuilder);

        //定义响应结果
        List<CoursePub> list = new ArrayList<>();
        QueryResult<CoursePub> queryResult = new QueryResult<>();
        //4.执行搜索
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
            //8.获取搜索结果
            SearchHits hits = searchResponse.getHits();
            //9.!!搜搜结果   匹配的总记录数
            long totalHits = hits.totalHits;
            //给相应结果 QueryResult的总记录数赋值
            queryResult.setTotal(totalHits);
            //10.获取匹配度高的记录
            SearchHit[] searchHits = hits.getHits();
            for (SearchHit hit : searchHits) {
                //11.取数据  放入返回结果
                CoursePub coursePub = new CoursePub();
                //源文档
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //Day取出id
                String id = (String) sourceAsMap.get("id");
                coursePub.setId(id);

                //取出name
                String name = (String) sourceAsMap.get("name");
//Day12-----------------------------------------------------
                //取出高亮字段name
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                if (highlightFields!=null){
                    //拿到name的高亮字段
                    HighlightField highlightFieldName = highlightFields.get("name");
                    if(highlightFieldName!=null){
                        //取出段信息
                        Text[] fragments = highlightFieldName.fragments();
                        //拼接高亮字段
                        StringBuffer stringBuffer = new StringBuffer();
                        for(Text text:fragments){
                            stringBuffer.append(text);
                        }
                        name = stringBuffer.toString();
                    }
                }
//Day12-----------------------------------------------------
                coursePub.setName(name);
                //图片
                String pic = (String) sourceAsMap.get("pic");
                coursePub.setPic(pic);
                //价格
                Double price = null;
                try {
                    if(sourceAsMap.get("price")!=null ){
                        price = (Double) sourceAsMap.get("price");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
                coursePub.setPrice(price);
                //旧价格
                Double price_old = null;
                try {
                    if(sourceAsMap.get("price_old")!=null ){
                        price_old = (Double) sourceAsMap.get("price_old");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                coursePub.setPrice_old(price_old);
                //将coursePub对象放入list
                list.add(coursePub);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //12.设置返回对象
        queryResult.setList(list);
        QueryResponseResult<CoursePub> queryResponseResult = new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);

        return queryResponseResult;
    }

    /**
     * Day_15_2 使用ES客户端向ES请求查询索引信息
     * @param id   某个课程的id
     * @return
     */
    public Map<String, CoursePub> getall(String id)  {
        //第一件事:定义一个搜索请求对象    ---相当于你要求情那张表,ES中的索引和表的概念类似
        SearchRequest searchRequest = new SearchRequest(index);
        //第二件事:指定type     ---这个type 没有实际意义,ES发展会全面取代
        searchRequest.types(type);



        //第三件事:定义SearchSourceBuilder  ---设置对原文档的搜索方法之类的
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //3-1:设置精确查询term
       searchSourceBuilder.query(QueryBuilders.termQuery("id",id));
        //3-2:过滤原字段 *(不设置源自段,取出所有字段  那些要哪些不要显示 )


        //第四件事:将builder设置到搜索对象中
        searchRequest.source(searchSourceBuilder);

        //第五件事:通过请求对象,发送请求对象
        //5-1:最终要返回的对象
        Map<String,CoursePub> map = new HashMap<>();
        //5-2:从搜索结果中取出数据
        try {
            SearchResponse search = restHighLevelClient.search(searchRequest);
            SearchHits hits = search.getHits();//搜索结果
            long totalHits = hits.getTotalHits(); //匹配到总记录数
            SearchHit[] hitsSource = hits.getHits();  //得到匹配高的文档
            //遍历结果
            for (SearchHit hit : hitsSource) {
                //获取源文档的内容
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //取出课程计划媒资信息
                String courseId = (String) sourceAsMap.get("id");
                String name = (String) sourceAsMap.get("name");
                String grade = (String) sourceAsMap.get("grade");
                String charge = (String) sourceAsMap.get("charge");
                String pic = (String) sourceAsMap.get("pic");
                String description = (String) sourceAsMap.get("description");
                String teachplan = (String) sourceAsMap.get("teachplan");
                //定义返回结果的map中的vaule
                CoursePub coursePub = new CoursePub();
                coursePub.setId(courseId);
                coursePub.setName(name);
                coursePub.setPic(pic);
                coursePub.setGrade(grade);
                coursePub.setTeachplan(teachplan);
                coursePub.setDescription(description);
                //封装map  key是数据的主键   vaule是数据的参数
                map.put(courseId,coursePub);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return map;
    }


    /**
     * Day_15@9:根据课程计划id查询,课程媒资信息
     * @param teachplanIds    多个具体课程的id
     * @return
     */
    public QueryResponseResult<TeachplanMediaPub>  getmedia(String[] teachplanIds) {
        //第一件事:定义一个搜索请求对象    ---相当于你要求情那张表,ES中的索引和表的概念类似
        SearchRequest searchRequest = new SearchRequest(media_index);
        //第二件事:指定type     ---这个type 没有实际意义,ES发展会全面取代
        searchRequest.types(media_type);

        //第三件事:定义SearchSourceBuilder  ---设置对原文档的搜索方法之类的
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //第四件事:将builder设置到搜索对象中
        searchRequest.source(searchSourceBuilder);
        //4-1:设置使用termsQuery根据多个id 查询
        searchSourceBuilder.query(QueryBuilders.termsQuery("teachplan_id",teachplanIds));
        //4-2:设置过滤字段
        String[] includes = media_source_field.split(",");
        //                              包括那些字段     不包括那些字段
        searchSourceBuilder.fetchSource(includes,new String[]{});
        //4-3:搜索信息配置到搜索对象
        searchRequest.source(searchSourceBuilder);
        //第五件事:通过请求对象,发送请求对象
        //5-1:定义最终返回对象类型
        ArrayList<TeachplanMediaPub> teachplanMediaPubList = new ArrayList<>();
        long total = 0;
        try {
            //5-2:拿到搜索的结果
            SearchResponse search = restHighLevelClient.search(searchRequest);
            SearchHits hits = search.getHits();//搜索结果
            total = hits.getTotalHits(); //匹配到总记录数
            SearchHit[] searchHits = hits.getHits();  //得到匹配高的文档
            for(SearchHit hit:searchHits){
                TeachplanMediaPub teachplanMediaPub= new TeachplanMediaPub();
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //取出课程计划媒资信息
                String courseid = (String) sourceAsMap.get("courseid");
                String media_id = (String) sourceAsMap.get("media_id");
                String media_url = (String) sourceAsMap.get("media_url");
                String teachplan_id = (String) sourceAsMap.get("teachplan_id");
                String media_fileoriginalname = (String) sourceAsMap.get("media_fileoriginalname");

                //存储课程计划信息
                teachplanMediaPub.setCourseId(courseid);
                teachplanMediaPub.setMediaUrl(media_url);
                teachplanMediaPub.setMediaFileOriginalName(media_fileoriginalname);
                teachplanMediaPub.setMediaId(media_id);
                teachplanMediaPub.setTeachplanId(teachplan_id);
                teachplanMediaPubList.add(teachplanMediaPub);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //数据集合
        QueryResult<TeachplanMediaPub> queryResult = new QueryResult<>();
        queryResult.setList(teachplanMediaPubList);
        queryResult.setTotal(total);
        QueryResponseResult<TeachplanMediaPub> queryResponseResult = new QueryResponseResult<>(CommonCode.SUCCESS,queryResult);
        return queryResponseResult;
    }
}
